package com.hitqz.robot.biz.flow.component.patrol;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hitqz.robot.api.business.entity.PatrolResultEntity;
import com.hitqz.robot.api.business.enums.ResultTypeEnum;
import com.hitqz.robot.api.business.model.dto.FlowContextDto;
import com.hitqz.robot.api.business.model.dto.FlowPatrolPreAndEndTicketsDto;
import com.hitqz.robot.api.business.model.dto.FlowPatrolTicketsDto;
import com.hitqz.robot.api.common.dto.warning.AddWarningDto;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.biz.util.PatrolConstant;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;

@Slf4j
@LiteflowComponent(value = "UpdateResult", name = "[巡检]更新报表")
@AllArgsConstructor
public class UpdateResult extends NodeComponent {

    private final PatrolItemService patrolItemService;

    private final PatrolObjectService patrolObjectService;

    private final PatrolResultService patrolResultService;

    private final PatrolObjectStandardService patrolObjectStandardService;

    private final PatrolCheckTypeService patrolCheckTypeService;

    private final ExecutorService customThreadPool;

    private final RobotConfigService robotConfigService;
    private final TicketsService ticketsService;

    private final AlarmRuleService alarmRuleService;

    @Override
    public void process() throws Exception {
        FlowContextDto dto = this.getRequestData();
        TicketsTask task = dto.getTicketsTask();
        FlowPatrolTicketsDto params = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolTicketsDto.class);
        if (params.getPatrolItemId() == null) {
            log.warn("没有检测项信息,不执行");
            return;
        }
        int index = params.getIndex();
        log.info("index:{}", index);
//        if (isNeedSkip(dto)){
//            //取上次的结果来用
//            index ++;
//
//        }else {
//            index = 0;
//        }
//        //更新index
//        params.setIndex(index);
//        task.setParseOrderParams(JSONObject.toJSONString(params));
        //处理结果
        String result = Optional.ofNullable(params.getResult()).orElse("");
        String visionUrl = Optional.ofNullable(params.getVisionUrl()).orElse("");
        try {
            String[] multiResult = result.split(" ");
            String[] multiVisionUrl = visionUrl.split(" ");
            result = Objects.equals(multiResult[index], "None") ? "" : multiResult[index];
            visionUrl = Objects.equals(multiVisionUrl[index], "None") ? "" : multiVisionUrl[index];
        } catch (Exception e) {
            log.error("解析结果失败,{}", e.getMessage());
        }
        Integer patrolItemId = params.getPatrolItemId();
        PatrolItem item = patrolItemService.getById(patrolItemId);
        PatrolObject patrolObject = patrolObjectService.getById(item.getPatrolObjectId());
        PatrolCheckType checkType = patrolCheckTypeService.getById(patrolObject.getPatrolCheckTypeId());
        PatrolObjectStandard standard = patrolObjectStandardService.getOne(Wrappers.<PatrolObjectStandard>lambdaQuery().eq(PatrolObjectStandard::getPatrolObjectId, patrolObject.getId()).last("limit 1"));
        PatrolResultEntity patrolResult = patrolResultService.getOne(Wrappers.<PatrolResultEntity>lambdaQuery()
                .eq(PatrolResultEntity::getTicketsId, dto.getTickets().getId())
                //.eq(PatrolResult::getTicketsTaskId, dto.getTicketsTask().getId())
                .eq(PatrolResultEntity::getItemId, params.getPatrolItemId())
                .last("limit 1")
        );
        patrolResult.setCheckTime(new Date());
        //处理结果数据
        patrolResult.setVisionResult(result);
        patrolResult.setConvertValue(result);
        //标准值 目前这边只处理浮点型的
        String normalValue = "";
        if (StrUtil.isNotBlank(item.getStandardValue())) {
            normalValue = item.getStandardValue();
            log.info("使用检测项的标准值:{}", normalValue);
        } else if (standard != null && StrUtil.isNotBlank(standard.getStandardValue())) {
            normalValue = standard.getStandardValue();
            log.info("使用检测对象的标准值:{}", normalValue);
        }
        if (Objects.equals(patrolObject.getIsConvert(), 1) && StrUtil.isNotBlank(result)) {
            // 转换后的值,用来比较和做数据统计的
            // 0-无返回 1-浮点型 2-单个枚举 3-多个枚举 4-字符串  todo 前端加5-数显
            String resultType = checkType.getResultType();
            ResultTypeEnum resultTypeEnum = ResultTypeEnum.fromType(resultType);
            if (resultTypeEnum != null) {
                switch (resultTypeEnum) {
                    //todo 新增和编辑去检查有没有 ,
                    case FLOAT -> {
                        if (!result.matches("-?\\d+(\\.\\d+)?")) {
                            log.warn("视觉结果不是浮点型数据,{},判断为检测失败", result);
                            result = "";
                            break;
                        }
                        String[] convertValues = patrolObject.getFloatConvert().split(",");
                        BigDecimal convertMinValue = new BigDecimal(convertValues[0]);
                        BigDecimal convertMaxValue = new BigDecimal(convertValues[1]);
                        BigDecimal visionResult = new BigDecimal(result);
                        double convertValue = visionResult.multiply(convertMaxValue.subtract(convertMinValue)).add(convertMinValue).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                        patrolResult.setConvertValue(String.valueOf(convertValue));
                        // 处理正常范围
                        if (StrUtil.isNotBlank(params.getVisionNormalValue())) {
                            String[] split = params.getVisionNormalValue().split(" ");
                            BigDecimal normalMinResult = new BigDecimal(split[Math.min(0, split.length - 1)]);
                            BigDecimal normalMaxResult = new BigDecimal(split[Math.min(1, split.length - 1)]);
                            double normalMin = normalMinResult.multiply(convertMaxValue.subtract(convertMinValue)).add(convertMinValue).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                            double normalMax = normalMaxResult.multiply(convertMaxValue.subtract(convertMinValue)).add(convertMinValue).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                            normalValue = normalMin + "," + normalMax;
                            log.info("使用视觉的标准值:{}", normalValue);
                        }
                    }
                    case SINGLE_ENUM, MULTI_ENUM -> {
                        //todo 新增和编辑去检查有没有 , 还有数量关系
                        String[] enumResults = patrolObject.getEnumResult().split(",");
                        String[] enumConverts = patrolObject.getEnumConvert().split(",");
                        for (int i = 0; i < enumResults.length; i++) {
                            if (Objects.equals(enumResults[i], result)) {
                                patrolResult.setConvertValue(enumConverts[i]);
                                break;
                            }
                        }
                    }
                    case LED -> {
                        //todo 前端要加
                        Integer afterPointCountConvert = patrolObject.getAfterPointCountConvert();
                        if (!result.contains(".") && Objects.equals(afterPointCountConvert, 0)) {
                            BigDecimal value = new BigDecimal(result);
                            BigDecimal point = BigDecimal.valueOf(Math.pow(10, afterPointCountConvert));
                            double v = value.divide(point).setScale(afterPointCountConvert, BigDecimal.ROUND_HALF_UP).doubleValue();
                            patrolResult.setConvertValue(String.valueOf(v));
                        }
                    }
                }
            }
        }

        int alarmLevel = 0;//报警级别--告警
        // 对比结果
        // 0-未检测 1-正常 2-异常 3-视觉识别失败
        patrolResult.setStatus(1);
        if (Objects.equals(checkType.getIsVision(), 1) && StrUtil.isBlank(result)) {
            //视觉检测项但是没有结果，判定为失败
            patrolResult.setStatus(3);
        } else if (StrUtil.isNotBlank(normalValue) && StrUtil.isNotBlank(patrolResult.getConvertValue())) {
            //都是转换后的进行对比
            String type = "-1";
            if (Objects.equals(checkType.getResultType(), "1") || Objects.equals(checkType.getResultType(), "5")) {
                //浮点和数显
                type = "2";
            } else if (Objects.equals(checkType.getResultType(), "2") || Objects.equals(checkType.getResultType(), "3")) {
                //枚举判定
                type = "1";
            }
            List<AlarmRule> alarmRuleList = alarmRuleService.list(Wrappers.<AlarmRule>lambdaQuery()
                    .eq(AlarmRule::getStandardId, standard.getId()));
            switch (type) {
                case "1" -> {
                    //值判定
                    patrolResult.setStatus(normalValue.contains(patrolResult.getConvertValue()) ? 1 : 2);
                    for (AlarmRule rule : alarmRuleList) {//设置告警等级
                        String ruleValue = rule.getVal();
                        if (ruleValue.contains(patrolResult.getConvertValue())) {
                            alarmLevel = Integer.parseInt(rule.getAlarmLevel());
                            break;
                        }
                    }
                }
                case "2" -> {
                    //区间判定 todo 新增和编辑去检查有没有 ,
                    String[] values = normalValue.split(",");
                    float minValue = Float.parseFloat(values[0]);
                    float maxValue = Float.parseFloat(values[1]);
                    float checkValue = Float.parseFloat(patrolResult.getConvertValue());
                    patrolResult.setStatus((minValue <= checkValue && checkValue <= maxValue) ? 1 : 2);
                    for (AlarmRule rule : alarmRuleList) {//设置告警等级
                        float ruleValueMin = Float.parseFloat(rule.getValueMin());
                        float ruleValueMax = Float.parseFloat(rule.getValueMax());
                        if (ruleValueMin <= checkValue && checkValue <= ruleValueMax) {
                            alarmLevel = Integer.parseInt(rule.getAlarmLevel());
                            break;
                        }
                    }
                }
            }
        }
        // 标准值
        patrolResult.setNormalValue(StrUtil.isNotBlank(normalValue) ? normalValue.replace(",", "~") + patrolObject.getUnit() : normalValue);
        // 展示在报表的值 转换后的值+单位
        String showValue = StrUtil.isBlank(patrolObject.getUnit()) ? patrolResult.getConvertValue() : StrUtil.isBlank(patrolResult.getConvertValue()) ? "" : patrolResult.getConvertValue() + patrolObject.getUnit();
        patrolResult.setShowValue(showValue);
        patrolResult.setMediaUrl(params.getMediaUrl());
        patrolResult.setVisionMediaUrl(visionUrl);
        if (StrUtil.isNotBlank(params.getSpecialCase())) {
            patrolResult.setAuditRemark(params.getSpecialCase());
        }
        patrolResultService.saveOrUpdate(patrolResult);
        // 上传到服务端

        // 报警  是否告警 0-否 1-是
        int alarm = Optional.ofNullable(standard.getAlarm()).orElse(1);
        if (Objects.equals(patrolResult.getStatus(), 2) && Objects.equals(alarm, 1)) {
            PatrolConstant.visionWaringFlag.set(true);
            String content = patrolResult.getItemName() + patrolResult.getShowValue() + ",异常(标准:" + patrolResult.getNormalValue() + ")";
            publishWarningEvent("检测告警", content, "999", "", alarmLevel, StrUtil.isBlank(patrolResult.getVisionMediaUrl()) ? patrolResult.getMediaUrl() : patrolResult.getVisionMediaUrl(), checkType.getName());
        }
        Runnable runnableTask = () -> {
            //上传到服务端 0-未上传 1-已上传 2-上传失败
            patrolResultService.upload2Server(patrolResult);
            patrolResult.setUploadStatus(1);
            patrolResultService.saveOrUpdate(patrolResult);
        };
        customThreadPool.submit(runnableTask);
    }


    private static void publishWarningEvent(String title, String content, String code, String suggestion, Integer level, String path, String remark) {
        AddWarningDto addWarningDto = new AddWarningDto();
        addWarningDto.setTitle(title);
        addWarningDto.setCode(code);
        addWarningDto.setContent(content);
        addWarningDto.setSuggestion(suggestion);
        addWarningDto.setLevel(level);
        addWarningDto.setPaths(path);
        SpringUtil.getApplicationContext().publishEvent(addWarningDto);
    }

    //一图多表情况
    private boolean isNeedSkip(FlowContextDto dto) {
        try {
            TicketsTask lastTicketsTask = dto.getLastTicketsTask();
            if (lastTicketsTask == null) {
                return false;
            }
            //当前参数
            TicketsTask task = dto.getTicketsTask();
            FlowPatrolTicketsDto params = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolTicketsDto.class);
            FlowPatrolPreAndEndTicketsDto endParams = JSONObject.parseObject(task.getParseOrderParams(), FlowPatrolPreAndEndTicketsDto.class);
            Integer currentTargetPosId = params.getPosId() != null ? params.getPosId() : (endParams.getEndPosId() != null ? endParams.getEndPosId() : null);
            //上一次的参数
            FlowPatrolTicketsDto lastParams = JSONObject.parseObject(lastTicketsTask.getParseOrderParams(), FlowPatrolTicketsDto.class);
            FlowPatrolPreAndEndTicketsDto lastEndParams = JSONObject.parseObject(lastTicketsTask.getParseOrderParams(), FlowPatrolPreAndEndTicketsDto.class);
            Integer lastTargetPosId = lastParams.getPosId() != null ? lastParams.getPosId() : (lastEndParams.getEndPosId() != null ? lastEndParams.getEndPosId() : null);
            if (!Objects.equals(currentTargetPosId, lastTargetPosId)) {
                return false;
            }
            if (!Objects.equals(params.getPoseGroupId(), lastParams.getPoseGroupId())) {
                return false;
            }
            if (!Objects.equals(params.getDetectEquipmentId(), lastParams.getDetectEquipmentId())) {
                return false;
            }
            Integer patrolItemId = params.getPatrolItemId();
            PatrolItem patrolItem = patrolItemService.getById(patrolItemId);
            PatrolObject patrolObject = patrolObjectService.getById(patrolItem.getPatrolObjectId());
            Integer lastPatrolItemId = lastParams.getPatrolItemId();
            PatrolItem lastPatrolItem = patrolItemService.getById(lastPatrolItemId);
            PatrolObject lastPatrolObject = patrolObjectService.getById(lastPatrolItem.getPatrolObjectId());
            // 同点位 同姿态 同相机 同检测类型
            if (!Objects.equals(patrolObject.getPatrolCheckTypeId(), lastPatrolObject.getPatrolCheckTypeId())) {
                return false;
            }
            log.info("当前工单任务与上一次工单任务点位、姿态、相机、检测类型相同");
            return true;
        } catch (Exception e) {
            return false;
        }
    }


}